﻿using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using ExUtil = System.Linq.Enumerable;

namespace Foundation.Core
{
    public class ServiceMethodSelectCollectionCreator : ISelectCollectionCreator
    {
        private readonly IServiceProvider _serviceProvider;

        public ServiceMethodSelectCollectionCreator(SelectItemLoadMethodOptions methodOptions, IServiceProvider serviceProvider)
        {
            if (methodOptions is null)
            {
                throw new ArgumentNullException(nameof(methodOptions));
            }

            MethodOptions = methodOptions;
            MethodInfo = methodOptions.Method;
            ServiceType = MethodInfo.DeclaringType;

            this._serviceProvider = serviceProvider;
        }

        public Type ServiceType { get; }

        public MethodInfo MethodInfo { get; }

        public SelectItemLoadMethodOptions MethodOptions { get; }

        public virtual async Task<SelectCollection> CreateAsync(string key, SelectCategory category, IDictionary<string, object> arguments, CancellationToken cancellationToken)
        {
            var service = _serviceProvider.GetRequiredService(ServiceType);

            //var parameters = MethodInfo.GetParameters();

            //if (parameters.Length > 1) throw new AppException($"{ServiceType}.{MethodInfo.Name}入参过多，无法执行！");

            //if (parameters.Length == 1 && parameters[0].ParameterType != typeof(CancellationToken))
            //{
            //    throw new AppException($"{ServiceType}.{MethodInfo.Name} 不接受参数类型{parameters[0].ParameterType}！");
            //}

            var parameters = MethodOptions.Parameters;
            var paramObjects = new List<object>((parameters?.Count).GetValueOrDefault());

            if (!parameters.IsNullOrEmpty())
            {
                var convert = SelectItemLoadMethodConverterFactory.GetConverter(_serviceProvider, MethodOptions);

                foreach (var p in parameters)
                {
                    //不支持的类型
                    if (!p.IsCancellationToken && !p.IsSimpleType && !p.IsSimpleListType && !p.IsOptional && p.ValueProviderType == null)
                    {
                        throw new BusinessException("select_method_creator_NonSuppert_Parameter", $"{key},对应的方法,输入参数“{p.PrameterName}”类型不支持！");
                    }

                    if (p.IsListType && p.ItemUnderlyingType == typeof(DateTime))
                    {
                        throw new BusinessException("select_method_creator_NonSuppert_Parameter", $"{key},对应的方法,输入参数“{p.PrameterName}”不支持可遍历的日期类型，请使用单个时间类型参数！");
                    }

                    if (p.IsCancellationToken)
                    {
                        paramObjects.Add(cancellationToken);
                        continue;
                    }

                    var input = p.HasDefaultValue ? p.DefaultValue : null;

                    var pResult = convert.ConvertValue(arguments, p);

                    if (pResult.IsSuccss)
                    {
                        input = pResult.Value;
                    }
                    else if (p.IsOptional && !pResult.IsFound)
                    {
                        input = p.HasDefaultValue ? p.DefaultValue : p.ParameterType.DefaultValue();
                    }
                    else
                    {
                        var message = pResult.IsFound ? (pResult.IsSupport ? $"参数[{p.PrameterName}]转换失败！" : $"不支持参数[{p.PrameterName}]类型") : $"未找到参数:{p.PrameterName}";
                        throw new BusinessException("select_method_creator_Parameter_Errror", message);
                    }

                    paramObjects.Add(input);
                }
            }

            var isTask = MethodOptions.IsAsync;

            var result = MethodInfo.Invoke(service, paramObjects.ToArray());
            if (isTask)
            {
                result = await (dynamic)result;
            }

            List<ISelectItem> items = result == null ? null : ExUtil.ToList(ExUtil.Cast<ISelectItem>((dynamic)result));

            var registrar = _serviceProvider.GetRequiredService<SelectFilterRegistrar>();

            var resultFilters = registrar.GetResultFilters(category);

            if (resultFilters != null)
            {
                var resultContext = new SelectResultContext(key, category, items);
                foreach (var resultFilter in resultFilters)
                {
                    resultFilter.OnCreated(resultContext);
                }
            }

            return new SelectCollection(category, items);
        }

    }

    public class ServiceMethodSelectCollectionCreatorFactory : ISelectCollectionCreatorFactory, ITransientDependency
    {
        private readonly IServiceProvider _serviceProvider;

        public ServiceMethodSelectCollectionCreatorFactory(IServiceProvider serviceProvider)
        {
            this._serviceProvider = serviceProvider;
        }

        public ISelectCollectionCreator Create(SelectItemOptions options)
        {
            var methodOptions = options.MethodOptions;
            if (methodOptions != null)
            {
                return new ServiceMethodSelectCollectionCreator(methodOptions, _serviceProvider);
            }

            throw new AppException($"{options.Key},{options.Category},未配置获取选项的方法信息。");
        }
    }
}
